#!/usr/bin/env bash

set -e

# shellcheck disable=SC1091
. /base-runner.sh

LOG=/tmp/qemu.log
LOCK=/tmp/qemu.lock

if [ -n "${CROSS_DEBUG}" ]; then
    set -x
fi

# arch in the rust target
arch="${1}"
shift

if [[ -z "${CROSS_RUNNER}" ]]; then
    if is_native_binary "${arch}"; then
        CROSS_RUNNER=native
    else
        CROSS_RUNNER=qemu-user
    fi
fi

# Ensure that the correct prefix is set even if the user has cleared the env.
# `@DEFAULT_QEMU_LD_PREFIX@` is replaced during image build.
export QEMU_LD_PREFIX=${QEMU_LD_PREFIX:-@DEFAULT_QEMU_LD_PREFIX@}

qarch=$(qemu_arch "${arch}")
case "${CROSS_RUNNER}" in
    native)
        exec "${@}"
        ;;
    qemu-user)
        exec "qemu-${qarch}" "${@}"
        ;;
    qemu-system)
        true
        ;;
    *)
        echo "Invalid runner: \"${CROSS_RUNNER}\"";
        echo "Valid runners are: native, qemu-user and qemu-system"
        exit 1
        ;;
esac

n="$(nproc)"
memory=1G
driver9p="virtio-9p-pci"
drivernet="virtio-net-pci"

# select qemu parameters
case "${arch}" in
    aarch64)
        # 8 is the max number of cpu supported by qemu-aarch64
        n=$(( n > 8 ? 8 : n ))
        opt="-machine virt -cpu cortex-a57"
        ;;
    armv7hf)
        opt="-machine virt"
        driver9p="virtio-9p-device"
        drivernet="virtio-net-device"
        ;;
    i686)
        opt="-append console=ttyS0"
        ;;
    mips|mipsel)
        # avoid kernel error
        # https://blahcat.github.io/2017/07/14/building-a-debian-stretch-qemu-image-for-mipsel/
        opt="-append nokaslr"
        n=1
        ;;
    mips64el)
        # avoid kernel error
        # https://blahcat.github.io/2017/07/14/building-a-debian-stretch-qemu-image-for-mipsel/
        opt="-append nokaslr -cpu MIPS64R2-generic"
        n=1
        ;;
    powerpc)
        opt="-append console=ttyPZ0"
        n=1
        ;;
    riscv64)
        opt="-machine virt"
        ;;
    powerpc64|powerpc64le)
        opt="-append console=hvc0 --nodefaults -serial stdio"
        ;;
    s390x)
        n=1
        driver9p="virtio-9p-ccw"
        drivernet="virtio-net-ccw"
        ;;
    sparc64)
        n=1
        driver9p+=",bus=pciB"
        drivernet+=",bus=pciB"
        ;;
    x86_64)
        opt="-append console=ttyS0"
        ;;
esac

(
    flock -n 200 || exit 0

    echo Booting QEMU virtual machine with $n cpus...

    QEMU_CMD="qemu-system-${qarch} \
        -m ${memory} \
        -smp ${n} \
        -nographic \
        -monitor none \
        -netdev user,id=net0,hostfwd=tcp::10022-:22 \
        -device ${drivernet},netdev=net0 \
        -kernel /qemu/kernel \
        -initrd /qemu/initrd.gz \
        ${opt} \
        -fsdev local,id=fs0,path=/target,security_model=mapped \
        -device ${driver9p},fsdev=fs0,mount_tag=target"

    touch "${LOG}"
    if [[ -n "${CROSS_DEBUG}" ]]; then
        (${QEMU_CMD} 2>&1 | tee -a "${LOG}") &
    else
        ${QEMU_CMD} >> "${LOG}" 2>&1 &
    fi
    qemu_pid=$!

    # wait for dropbear
    for _ in $(seq 240); do
        if grep -q "Not backgrounding" "${LOG}"; then
            READY=1
            break
        elif ! (ps -p "${qemu_pid}" >/dev/null 2>&1); then
            # qemu command failed and exited early
            exit 1
        fi
        sleep 0.5s
    done

    if [ -z "${READY}" ]; then
        if [ -n "${CROSS_DEBUG}" ]; then
            echo "Not ready but continuing because CROSS_DEBUG is set"
        else
            echo "Qemu is not ready after ${SECONDS} seconds..."
            echo "Set the environment variable CROSS_DEBUG=1 to debug"
            echo "Last 100 lines of qemu output:"
            tail -n 100 "${LOG}"
            exit 1
        fi
    fi

    echo "Booted in ${SECONDS} seconds"

) 200>"${LOCK}"

if [[ -t 1 ]] && [[ -t 2 ]]; then
  tty_flag='-t'
fi

exec dbclient ${tty_flag} -p 10022 -y -y root@localhost "${@}"
